package org.fast.cms.common.web.aspect;

import java.util.ArrayList;
import java.util.List;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authz.UnauthorizedException;
import org.fast.cms.common.domain.response.JsonResponse;
import org.fast.cms.common.enums.MessageCodeEnum;
import org.fast.cms.common.exception.ApiException;
import org.fast.cms.common.exception.BusinessException;
import org.fast.cms.common.exception.InvalidParameterException;
import org.fast.cms.common.exception.UpdateConflictException;
import org.fast.cms.common.utils.MessageUtils;
import org.fast.cms.common.utils.string.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

@RestController
@ControllerAdvice
public class GlobalExceptionHandler {

    private Logger log = LoggerFactory.getLogger("error");

    /**
     * 拦截未知异常
     * @param ex
     * @return
     */
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(Exception.class)
    public JsonResponse<Void> handleException(Exception ex) {
        JsonResponse<Void> reps = new JsonResponse<Void>(
                MessageUtils.getLocaleMessageInfo(MessageCodeEnum.UNKNOWN_ERROR));
        log.error("Unknown Error", ex);
        return reps;
    }

    @ResponseStatus(HttpStatus.OK)
	@ExceptionHandler(InvalidParameterException.class)
	public JsonResponse<Void> handlerInvalidParameterException(InvalidParameterException ex) {
		JsonResponse<Void> reps = new JsonResponse<Void>();
		reps.setCode(MessageCodeEnum.INVAID_PARAM.getCode());
		reps.setMessage(ex.getMsg());
		log.warn("Business Error " + ex.getMsg(), ex);
		return reps;
	}
	
	@ResponseStatus(HttpStatus.OK)
	@ExceptionHandler(UpdateConflictException.class)
	public JsonResponse<Void> handlerUpdateConflictException(UpdateConflictException ex) {
		JsonResponse<Void> reps = new JsonResponse<Void>();
		reps.setCode(MessageCodeEnum.UPDATE_CONFLICT.getCode());
		reps.setMessage(ex.getMsg());
		log.warn("Business Error " + ex.getMsg(), ex);
		return reps;
	}
	
	
	@ResponseStatus(HttpStatus.OK)
	@ExceptionHandler(ApiException.class)
	public JsonResponse<Void> handlerApiException(ApiException ex) {
		JsonResponse<Void> reps = new JsonResponse<Void>();
		reps.setCode(MessageCodeEnum.FAILED.getCode());
		reps.setMessage(ex.getMsg());
		log.error("Server Api Error ", ex);
		return reps;
	}

    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(BusinessException.class)
    public JsonResponse<Void> handlerException(BusinessException ex) {
        JsonResponse<Void> reps = new JsonResponse<Void>();
        reps.setCode(StringUtils.isEmpty(ex.getErrorCode()) ? MessageCodeEnum.FAILED.getCode() : ex.getErrorCode());
        reps.setMessage(ex.getMessage());
        return reps;
    }

    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public JsonResponse<List<BindingError>> handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {

        log.warn("input params validate error", ex);

        List<BindingError> bindingErrors = new ArrayList<BindingError>();
//        String msg = 
        		processErrors(ex.getBindingResult(), bindingErrors);
        JsonResponse<List<BindingError>> ajaxResponse =
                new JsonResponse<List<BindingError>>(MessageUtils.getLocaleMessageInfo(MessageCodeEnum.PARAM_VALID_ERROR));
        ajaxResponse.setData(bindingErrors);
        return ajaxResponse;
    }

    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(BindException.class)
    public JsonResponse<List<BindingError>> handleBindException(BindException ex) {

        log.warn("input params validate error", ex);

        List<BindingError> bindingErrors = new ArrayList<BindingError>();
        processErrors(ex.getBindingResult(), bindingErrors);
        JsonResponse<List<BindingError>> ajaxResponse =
                new JsonResponse<List<BindingError>>(MessageUtils.getLocaleMessageInfo(MessageCodeEnum.PARAM_VALID_ERROR));
        ajaxResponse.setData(bindingErrors);
        return ajaxResponse;
    }

    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public JsonResponse<Void> handlerMissingServletRequestParameterException(MissingServletRequestParameterException ex) {
    	JsonResponse<Void> reps = new JsonResponse<Void>(MessageUtils.getLocaleMessageInfo(MessageCodeEnum.MISSING_PARAM));
        return reps;
    }
 
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(UnauthorizedException.class)
    public JsonResponse<Void> handlerUnauthorizedException(UnauthorizedException ex) {
        JsonResponse<Void> reps = new JsonResponse<Void>(MessageUtils.getLocaleMessageInfo(MessageCodeEnum.UN_AUTHORIZED));
        log.warn("UN_AUTHORIZED : " + ex.getMessage());
        return reps;
    }
    
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(AuthenticationException.class)
    public JsonResponse<Void> handlerAuthenticationException(AuthenticationException ex) {
        JsonResponse<Void> reps = new JsonResponse<Void>(MessageUtils.getLocaleMessageInfo(MessageCodeEnum.AUTHETICATION_FAILED));
        log.warn("AuthenticationException : " + ex.getMessage());
        return reps;
    }

    private String processErrors(BindingResult result,
                                 List<BindingError> bindingErrors) {
        StringBuilder sb = new StringBuilder("参数错误");
        for (FieldError error : result.getFieldErrors()) {
            BindingError be = new BindingError();
            be.setMessage(error.getDefaultMessage());
            be.setName(error.getField());
            bindingErrors.add(be);
            sb.append("\n");
            sb.append(be.getMessage());
        }
        return sb.toString();
    }
}
